# -*- coding: utf-8 -*-
# @Author: felix


"""
专门用来 用例Excel参数化

读取Yaml文件
导入yaml 包   : pip install pyyaml

"""
import datetime
import os.path,uuid
import allure
import copy,os
import pandas as pd
import json
import ast


import yaml
from PytestApi.apirun_v9.core.globalContext import g_context
from PytestApi.apirun_v9.utils.logRecord import Logger

current_date = datetime.datetime.now().strftime('%Y%m%d%H%M%S')
log_filename = f'logdata_{current_date}.log'

print("日志文件",log_filename)


log_record = Logger('ExcelCaseParse_logger', log_filename)

class excel_Op:

    # def __init__(self):
    #     # 调用全局变量方法
    #     self.load_context_from_yaml("../example/")

    def read_yaml(self,filePath):
        log_record.logger.info("读取yaml文件")
        caseInfos = []
        with open(filePath, 'r', encoding='utf-8') as f:
            # 加载所有的数据
            caseinfo = yaml.full_load(f)
            caseInfos.append(caseinfo)   # 列表嵌套字典的数据 [{yaml里面的数据}]
            return caseInfos

    # 获取以context开头 .xlsx结尾的内容，并放入到公共参数中去!
    # 公共参数处理逻辑
    # openpyxl是pandas用于读取.xlsx文件的引擎之一
    # pip install pandas openpyxl
    def load_context_from_excel(self,folder_path):
        """

        :param folder_path:  文件路径
        :return:
        """
        try:
            excel_file_path = os.path.join(folder_path, 'context.xlsx')  # 会将 路径 和文件进行拼接

            print("load_context_from_excel:",excel_file_path)

            # 读取excl文件
            ef = pd.read_excel(excel_file_path,engine='openpyxl')

            print("excel文件:\n", ef)


            #初始化一个空字典来存储结果
            data = {
                "_database": {}
            }

            # 遍历DataFrame的每一行

            for index,row in ef.iterrows():
                print("row",row)
                if row['类型'] == '变量':
                    # 如果Type是“变量”，则将Description作为键，Value作为值添加到result字典
                    print("row值:", row['变量值'])
                    print("row描述:", row['变量描述'])
                    data[row['变量描述']] = row['变量值']

                    print("row描述111", row['变量描述'])
                elif '数据库' in row['类型']:
                    # 如果Type包含“数据库”,.则解析value列中的JSON字符串
                    db_name = row["变量描述"] # 提取数据库名
                    db_config = json.loads(row["变量值"]) # 将Json字符串转为字典
                    # 将数据库配置添加到result字典的_database键下
                    data["_database"][db_name] = db_config

            if data: g_context().set_by_dict(data)

            print("全局变量:",g_context().show_dict())

            print("data_excel:",data)

        except Exception as e:
            print(f"装载excel文件错误:{str(e)}")
            return False





    def load_excel_files(self,config_path):
        """

        返回满足条件的yaml文件
        :param config_path: Yaml文件存在的路径
        :return: yaml_caseInfos
        """

        # current_path = os.getcwd()  # os.getcwd() 返回的是当前工作目录，而不是文件所在的目录

        """
        # 这里 __file__ 是当前执行文件（在这个例子中就是 A 文件）的路径，
        通过 os.path.abspath 将其转换为绝对路径，再使用 os.path.dirname 获取其所在的目录路径。
        这样无论从哪个文件调用 A 文件，都能正确地获取到 A 文件所在的目录。
        """
        current_path = os.path.dirname(os.path.abspath(__file__))
        log_record.logger.info(f"当前路径:{current_path}")
        parent_path = os.path.dirname(current_path)
        # parent_path = r'D:\HCTest\pythonProject\Request\PytestApi\apirun_v9'
        log_record.logger.info(f"当前路径父级:{parent_path}",)


        excel_caseInfos = [] # 存储所有的数据

        suite_folder = parent_path + config_path

        log_record.logger.info(f"excel_case路径:{suite_folder}")

        # TODO 1 调用全局变量方法,将变量写入全局
        self.load_context_from_excel(suite_folder)

        # TODO 2 扫描文件夹下的符合用例的yaml文件，
        file_names = [(int(f.split("_")[0]), f) for f in os.listdir(suite_folder) if
                      f.endswith(".xlsx") and f.split("_")[0].isdigit()]

        log_record.logger.info(f"测试用例文件:{file_names}")

        # TODO 3 排序之后只保留文件名
        file_names.sort()
        file_names = [f[-1] for f in file_names]
        log_record.logger.info(f"排序后的测试用例文件:{file_names}")

        # 因为需要excel的参数一一对应起来关键字，所以需要结合：keywords.yaml中的参数描述变成字典格式。
        current_dir = os.path.abspath(os.path.dirname(__file__))  # 获取当前文件的绝对路径
        parent_dir = os.path.dirname(current_dir)  # 基于当前路径获取上一层路径
        keywords_file_path = os.path.join(parent_dir, "extend/keywords.yaml")  # 进行拼接
        keywords_info = {}
        with open(keywords_file_path, "r", encoding='utf-8') as rfile:
            keywords_info = yaml.full_load(rfile)


        # TODO 4 遍历文件名并且加入到yaml_caseInfos文件中
        for file_name in file_names:
            file_path = os.path.join(suite_folder, file_name)
            log_record.logger.info(f"测试用例路径:{file_path}")

            # TODO1: 读取excel
            data = pd.read_excel(file_path, sheet_name=0)
            data = data.where(data.notnull(), None) # 将非空值保留，空数据用None替换
            data = data.to_dict(orient='records') # 使用字典格式现实
            log_record.logger.info(f"测试用例data:{data}")

            # 初始化一个字典，用例存在某一条测试用例
            current_test_case = None

            for row in data:
                print("row",row)   # 打印每一行数据，除了表头
                # 判断是否有测试用例标题，如果有的话，代表是一个测试用例开始，直到遇到下一个标题，就从头开始

                # TODO 1: 检查当前行是否包含有效的测试用例标题，有则代表对应的起始位
                if pd.notna(row["测试用例标题"]):
                    # 如果已经构建完毕那么需要当前加进去到对应的测试用例当中
                    if current_test_case is not None:
                        excel_caseInfos.append(current_test_case)



                    # 初始化一个测试用例字典

                    current_test_case =  {
                        "desc": row['测试用例标题'],
                        "steps": []
                    }

                # TODO 2-1: 初始化步骤的值
                steps = {
                    row["步骤描述"]: {
                        "关键字": row["关键字"]
                    }
                }

                # TODO 2-2: 考虑步骤当中对应的每个参数
                parameter = []
                for key,value in row.items():
                    if "参数_" in key:
                        try:
                            # 尝试将字符串转换为python对象
                            # http://xxxxxx   此格式以下方法处理不了，所以使用try，捕获不处理，直接append
                            value = ast.literal_eval(value)
                        except:
                            pass

                        parameter.append(value)

                # TODO 2-3: 把对应的值和KEY，一一对应起来，这样我们才能发送请求
                # dict_parameter = {k:v for k,v in zip(key,value)}
                dict_parameter = {k:v for k,v in zip(keywords_info[row["关键字"]], parameter)}
                steps[row["步骤描述"]].update(dict_parameter)

                # 步骤加到当前测试用例来
                current_test_case["steps"].append(steps)

            if current_test_case is not None:
                excel_caseInfos.append(current_test_case)


        log_record.logger.info(f"获取excel测试用例信息:{excel_caseInfos}")
        return excel_caseInfos


    def excel_case_parser(self,config_path):

        """
        返回指定条件的格式

        :param config_path: 文件路径
        :return:
            return {
                    "case_infos": case_infos, # 所有的测试用例[]
                "case_names": case_names  # 所有测试用例对应的标题[]
            }
        """

        # TODO 1 : 对应固定格式

        case_infos = []
        case_names = []

        # TODO 2 : 调用对应的方法，拿到所有的数据
        excel_caseinfos = self.load_excel_files(config_path)

        # TODO 3 : 统一处理成一样的格式 (后面excel一样的处理)

        for caseinfo in excel_caseinfos:
            caseinfo.update({"_case_name": caseinfo["desc"]})

            case_infos.append(caseinfo)    # 所有的测试用例[]
            case_names.append(caseinfo["desc"])  # 所有测试用例对应的标题[]

        log_record.logger.info(f"获取Excel测试用例信息:{case_infos}")
        log_record.logger.info(f"获取Excel测试用例名称:{case_names}")
        return {
                "case_infos": case_infos, # 所有的测试用例[]
                "case_names": case_names  # 所有测试用例对应的标题[]
            }





if __name__ == '__main__':
    # pass
    excel_data = excel_Op()
    current_path = os.getcwd()
    print(current_path)
    parent_path = os.path.dirname(current_path)
    print("parent_path:",parent_path)
    excel_file_path = parent_path + "\example"
    print("excel_file_path:",excel_file_path)
    # excel_data.load_context_from_excel(excel_file_path)
    # current_path =os.path.dirname(os.path.abspath(__file__))
    # log_record.logger.info(f"当前路径:{current_path}")

    excel_data.excel_case_parser("\example")

